<?php
namespace slinks\common\util;

/**
 * Class proxies a normal array and allows clients to specify that value that is returned for a given key. 
 * This allows a given array to return multiple values for the same key.
 * Class implements php Array interfaces so this class can be used as a standard array. 
 * 
 * NOTE: when used as an array the ArrayProxy is unmodifiable.
 * 
 * @author navid
 */
class ArrayProxy implements \ArrayAccess, \Iterator, \Countable{
    
    private $array;
    private $closure;
    /**
     * Constructs a new array proxy.
     * @param array $array the array to be proxied.
     * @param closure that accepts 1 argument which is the array value to be proxied. 
     *        Ex: function($value){
     *              return new Proxy($value); 
     *            }
     */
    public function __construct(array $array,$closure) {
        $this->array = $array;
        $this->closure = $closure;
    }
    
    public function offsetSet($offset, $value) {
        throw new \LogicException('You can\'t set this array.');
    }

    public function offsetExists($offset) {
        return isset($this->array[$offset]);
    }

    public function offsetUnset($offset) {
        throw new \LogicException('You can\'t unset this array.');
    }

    public function offsetGet($offset) {
        $ret = null;
        if (isset($this->array[$offset])) {
            $closure = $this->closure;
            $ret = $closure($this->array[$offset]);
        }
        return $ret;
    }

    public function rewind() {
        reset($this->array);
    }

    public function current() {
        $current = current($this->array);
        if ($current !== false) {
            $closure = $this->closure;
            $current = $closure($current);
        }
        return $current;
    }

    public function key() {
        return key($this->array);
    }

    public function next() {
        $next = next($this->array);
        if ($next !== false) {
            $closure = $this->closure;
            $next = $closure($next);
        }
        return $next;
    }

    public function valid() {
        return $this->current() !== false;
    }

    public function count() {
        return count($this->array);
    }
    
}

?>
